/*
 * Copyright (c) 2020. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
 * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
 * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
 * Vestibulum commodo. Ut rhoncus gravida arcu.
 */

package com.gehj.uhttp;



import android.content.Context;

import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

import com.gehj.alluitls.androidUtils.LogUtil;
import com.gehj.alluitls.androidUtils.SharePreferenceUtils;
import com.gehj.uhttp.CallBack.MyJsonCallback;
import com.gehj.uhttp.listener.DisposeDataListener;

import java.io.File;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;

/**
 * OkhttpUtils
 * https://blog.csdn.net/lmj623565791/article/details/48129405
 * 张鸿洋的文章 -->可以参考看，尤其是双向验证
 * @author gehj
 * @time 2020/10/13 22:30
 */

public class OkhttpUtils implements LifecycleObserver {
    private static OkHttpClient client;
    private static Request request;
    private static Call call;
    private static Context mContext;
    private static String mTAG;
    public static final int TIME_OUT = 30;//超时时间
    /*public OkhttpUtils(Context mContext) {
        this.mContext = mContext;
    }*/
    private OkhttpUtils(){}

    /**
     * 单例
     * */
    public static OkhttpUtils getInstance(String TAG) {
        mTAG = TAG;
        return OkhttpUtils.SingletonHolder.instance;
    }

    private static class SingletonHolder {
        private static OkhttpUtils instance = new OkhttpUtils();
    }

    public static void init(Context context){
       mContext = context;
    }


    /**
     * 获取OkHttpClient
     * @return the client
     */
    public static OkHttpClient getClient() {
        //OkHttpClient.Builder okhttpBuilder = new OkHttpClient.Builder();
        OkHttpClient.Builder okhttpClientBuilder = Singleton.getOkhttpClientBuilderInstance();
        //okhttpClientBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
        //okhttpClientBuilder.readTimeout(TIME_OUT,TimeUnit.SECONDS);
       // okhttpClientBuilder.writeTimeout(TIME_OUT,TimeUnit.SECONDS);
        //转发与重定向的区别 https://blog.csdn.net/xianyadong/article/details/81230808
        //okhttpClientBuilder.followRedirects(true);//允许重定向；
        //支持自定义的证书，支持官方购买的证书
        /*okhttpClientBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });*/
        //https证书处理
        /*okhttpClientBuilder.sslSocketFactory(HttpsUtils.initSSLSocketFactory(),
                HttpsUtils.initTrustManager());*/
        //增加cookie，没有永久保存
        /*okhttpClientBuilder.cookieJar(new SimpleCookieJar()); */

        //根据项目进行添加
        //okhttpClientBuilder.addInterceptor(new TokenInterceptor(mContext));

        // client = Singleton.getOkhttpClientInstance();
        //client.cookieJar();
        //return client;
        return okhttpClientBuilder.build();
    }




/*-----------------------------以下get请求-----------------------*/
    /**
     * get请求-没有参数 - 可以统一处理的callback
     * @param url
     * @return
     */
    public static void Get_common(String url,DisposeDataListener listener) {
        Get_common_params_headers(url, null, null,listener);
    }

    /**
     * get请求-只有参数-没有请求头
     * 可以统一处理的callback
     * @param url
     * @param params
     * @return
     */
    public static void Get_common_params(String url, Map params,DisposeDataListener listener) {
         Get_common_params_headers(url, params, null,listener);
    }


    /**
     * 可以带请求头的Get请求,可以带参数的get，直接往后拼接
     * 可以统一处理的callback
     * @param url
     * @param params //请求参数 ？=往后添加
     * @param headers //header的参数
     */
    public static void Get_common_params_headers(String url,
                                                 Map<String,String> params,
                                                 Map<String,String> headers,
                                                 DisposeDataListener listener) {

        StringBuilder urlBuilder = new StringBuilder(url).append("?");
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                urlBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
        }

        //添加请求头
        //添加请求头
        Headers.Builder mHeaderBuild = new Headers.Builder();
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                mHeaderBuild.add(entry.getKey(), entry.getValue());
            }
        }
        Headers mHeader = mHeaderBuild.build();

        //创建Request对象
        request = new Request.Builder()
                .url(urlBuilder.substring(0, urlBuilder.length() - 1))
                .headers(mHeader)
                .tag(mTAG)
                .build();
        //创建执行任务的call对象

        call = getClient()
                .newCall(request);
        //执行异步任务
        call.enqueue(new MyJsonCallback(listener));
    }






    /**
     * 不带任何参数的get请求
     * Gets data.
     * @param url      the url
     * @param callback the callback
     */
    public static void get_data(String url,
                                Callback callback) {
        //创建Request对象
        request = new Request.Builder()
                .url(url)
                .tag(mTAG)
                .build();
        //创建执行任务的call对象

        call = getClient()
                .newCall(request);
        //执行异步任务
        call.enqueue(callback);
    }


    /**
     * 带token的get请求：普通
     * @param url      the url
     * @param callback the callback
     */
    public static void get_token_Json(String url,
                                      Callback callback) {
        //创建Request对象
        request = new Request.Builder()
                .url(url)
                .tag(mTAG)
                .build();
        //创建执行任务的call对象

        call = getClient() //好司机商务端请求头增加token；
                .newBuilder()
                .addInterceptor(new TokenInterceptor(mContext)).build()
                .newCall(request);
        //call = getClient().newCall(request);
        //执行异步任务
        call.enqueue(callback);
    }


    /**
     * 带类似与form的请求参数,带token的get请求
     *
     * @param urlBuilder      the url+参数
     * @param callback the callback
     */
    public static void get_addParam_token_Json(HttpUrl.Builder urlBuilder,
                                      Callback callback) {

        /*代码提示
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        urlBuilder.addQueryParameter("access_token","adadadad2daq4fca");
        urlBuilder.addQueryParameter("uid","xxxadadadad2daq4fca00");
        **/

        //创建Request对象
        request = new Request.Builder()
                .get()
                .url(urlBuilder.build())
                .tag(mTAG)
                .build();
        //创建执行任务的call对象

        call = getClient() //好司机商务端请求头增加token；
                .newBuilder().addInterceptor(new TokenInterceptor(mContext)).build()
                .newCall(request);
        //call = getClient().newCall(request);
        //执行异步任务
        call.enqueue(callback);
    }













    /*-----------------------以下post请求-----------------------*/
    /**
     * 不带参数的post请求
     * post请求-带form参数
     * @param url
     * @param listener 成功失败的回调
     */
    public static void post_common(String url,
                                    DisposeDataListener listener){

        post_common_params_heads(url,null,null,listener);
    }


    /**
     * post请求-带form参数
     * @param url
     * @param params
     * @param listener 成功失败的回调
     */
    public static void post_common_params(String url,
                                          final Map<String, String> params ,
                                          DisposeDataListener listener){

        post_common_params_heads(url,params,null,listener);
    }

    /**
     *
     * post请求-带form参数，带请求头
     * @param url
     * @param params
     * @param headers
     * @param listener 成功失败的回调
     */
    public static void post_common_params_heads(String url,
                                                final Map<String, String> params ,
                                                Map<String, String> headers,
                                                DisposeDataListener listener
                                                ){

        FormBody.Builder mFormBodyBuild = new FormBody.Builder();
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                mFormBodyBuild.add(entry.getKey(), entry.getValue());
            }
        }

        //添加请求头
        Headers.Builder mHeaderBuild = new Headers.Builder();
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                mHeaderBuild.add(entry.getKey(), entry.getValue());
            }
        }

        FormBody mFormBody = mFormBodyBuild.build();
        Headers mHeader = mHeaderBuild.build();
        Request request = new Request.Builder().url(url).
                post(mFormBody).
                headers(mHeader)
                .tag(mTAG)
                .build();

        call = getClient() //好司机商务端请求头增加token；
                .newCall(request);
        call.enqueue(new MyJsonCallback(listener));
    }


    /**
     * 带token的post请求
     * @param url      the url
     * @param builder  the builder
     * @param callback the callback
     */
    public static void post_token_Json(String url,
                                       FormBody.Builder builder,
                                       Callback callback) {

        /*代码提示
         FormBody.Builder builder = new FormBody.Builder();
         builder.add("code", "gehj");
         builder.add("password", "20");
         builder.add("serialIds", "2143,3404");
         builder.add("v", "4.0.0");**/

        request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .tag(mTAG)
                .build();
        call = getClient() //好司机商务端请求头增加token；
                .newBuilder().addInterceptor(new TokenInterceptor(mContext)).build()
                .newCall(request);
        call.enqueue(callback);
    }


    /**
     * 普通的post请求
     * */
    public static void post_common_Json(String url,
                                        FormBody.Builder builder,
                                        Callback callback) {
    /* 代码提示
        FormBody.Builder builder = new FormBody.Builder();
        //key需要重写；
        builder.add("code", "gehj");
        builder.add("password", "20");
        builder.add("serialIds", "2143,3404");
        builder.add("v", "4.0.0");**/
        request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .tag(mTAG)
                .build();
        call = getClient()
                .newCall(request);
        call.enqueue(callback);

    }

    /**
     * Login post get data.
     *
     * @param url      the url
     * @param userName the user name
     * @param pwd      the pwd
     * @param callback the callback
     */
    public static void login_post_GetData(String url,
                                          String userName, String pwd,
                                          Callback callback) {

        //1需要些的参数
        FormBody.Builder builder = new FormBody.Builder();
        builder.add("grant_type", "password");
        builder.add("clientType", "SH");
        builder.add("username", userName);
        builder.add("password", pwd);

        /**
         * 登录时请求头需要添加baseToken
         */
        String baseToken = SharePreferenceUtils.getString(mContext, GlobleURL_GoodDriver_Business.BASE_TOKEN);
        request = new Request.Builder()
                .addHeader(GlobleURL_GoodDriver_Business.Authorization, baseToken)
                .url(url)
                .post(builder.build())
                .tag(mTAG)
                .build();
        call = getClient().newCall(request);
        call.enqueue(callback);
    }



    /**
     *
     * post请求需要传json的请求 bean转json
     * @param url
     * @param json
     * @param callback
     */
    public static void post_jsonParmas(String url,
                                     String json,
                                     Callback callback) {
        /*  代码提示
         *"{\"deviceType\": \"1\",\"appType\": \"1\",\"appVersion\": \"2.9.0\"}"*
         * 用gson转实体即可
         **/
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody requestBody = RequestBody.create(json, mediaType);


        request = new Request.Builder()
                .url(url)
                .method("POST", requestBody)
                .addHeader("Content-Type", "application/json")
                .tag(mTAG)
                .build();
        call = getClient() //好司机商务端请求头增加token;
                .newCall(request);
        call.enqueue(callback);

    }








/*----------------上传文件 -------------------------*/
    /**
     * Up load img. 单张照片上传
     * @param url      the url
     * @param file     the file ：从相册中取；
     * @param params   the params ：map类型参数
     * @param callback the callback
     *                 certFile
     */
    public static void upLoadImg_token(String url, String key,File file,
                                       final Map<String, String> params,//必须指定泛型，否则无法遍历
                                       Callback callback) {
        MediaType MEDIA_TYPE = MediaType.parse("image/*");
        //2.构建MultipartBody
        //2.1 添加文件
        MultipartBody.Builder multipartBody = new MultipartBody.Builder().
                setType(MultipartBody.FORM);

        //RequestBody fileBody = null;
        if (null != file) {
            RequestBody fileBody = RequestBody.create(file, MEDIA_TYPE);
            multipartBody.addFormDataPart(key, file.getName(), fileBody);
        }


        //3.2 添加其他参数
        for (Map.Entry<String, String> entry : params.entrySet()) {
            multipartBody.addFormDataPart(entry.getKey(), entry.getValue());
        }


        //4.构建请求
        Request request = new Request.Builder()
                .url(url)
                .post(multipartBody.build())
                .tag(mTAG)
                .build();

        call = getClient() //好司机商务端请求头增加token；
                .newBuilder().addInterceptor(new TokenInterceptor(mContext)).build()
                .newCall(request);
        call.enqueue(callback);
    }

    /**
     * Up load imgs.
     *
     * @param url      the url
     * @param mImgUrls the m img urls
     * @param callback the callback
     * @param params   the params
     */
    /*上传多张图片*/
    public static void upLoadImgs(String url,String key, String[] mImgUrls,
                                  final Map<String, String> params,
                                  Callback callback) {
        MediaType MEDIA_TYPE_JPEG = MediaType.parse("image/jpeg");
        MultipartBody.Builder builder = new MultipartBody.Builder().
                setType(MultipartBody.FORM);

        if ( mImgUrls != null){
            for (int i = 0; i < mImgUrls.length; i++) {
                File f = new File(mImgUrls[i]);
                //图片存3个参数;
                builder.addFormDataPart(key, f.getName(), RequestBody.create(f, MEDIA_TYPE_JPEG));
            }
        }

        //添加其他参数;
        /*builder.addFormDataPart("billSerial", params[0])
                .addFormDataPart("token", params[1])
                .addFormDataPart("longitude", params[2])
                .addFormDataPart("latitude", params[3])
                .addFormDataPart("locationName", params[4])
                .addFormDataPart("shootingTime", params[5]);*/


        //3.2 添加其他参数
        if (null != params ){
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.addFormDataPart(entry.getKey(), entry.getValue());
            }
        }




        MultipartBody requestBody = builder.build();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)//添加请求体
                .tag(mTAG)
                .build();
        call = getClient()//好司机商务端请求头增加token；
                .newBuilder().addInterceptor(new TokenInterceptor(mContext)).build()
                .newCall(request);
        call.enqueue(callback);

    }

    /**
     * delete 请求
     * */
    public static  void  delete(HttpUrl.Builder urlBuilder,Callback callback) {

         /*代码提示
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        urlBuilder.addQueryParameter("access_token","adadadad2daq4fca");
        urlBuilder.addQueryParameter("uid","xxxadadadad2daq4fca00");

        **/
        request = new Request.Builder()
                .url(urlBuilder.build())
                .delete()
                .tag(mTAG)
                .build();
        call = getClient() //好司机商务端请求头增加token；
                .newBuilder().addInterceptor(new TokenInterceptor(mContext)).build()
                .newCall(request);
        call.enqueue(callback);
    }



    /**
     * Cancel all call.
     * //IMPORTANT:这个方法有危险，fragment切换时候，
     *      上一个fragment在onDetach调用这个方法，下一个fragment则不能执行网络请求；
     */
    public static void cancelAllCall() {
        getClient().dispatcher().cancelAll();
    }

    /**
     * 取消正在执行的请求，fragment快速切换防止空指针
     * 其实OnLifecycleEvent没有用到 -- Activity好用，Fragment生命周期api并不友好；
     * */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public static void cancelTagCall(Object tag) {
        LogUtil.e("cancelCall",tag+"");
        if (mTAG == null) return;

            for (Call call : getClient().dispatcher().runningCalls()) {
                if (mTAG.equals(call.request().tag())){
                    call.cancel();
                }


        }

    }
}
